/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-12-10     xu       the first version
 */
#include "kvdb.h"

#define DBG_TAG "key"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

kvdb_t kvdb_open(const char* part)
{
    rt_mutex_t mutex = rt_mutex_create(part, RT_IPC_FLAG_FIFO);
    if (mutex == RT_NULL) {
        LOG_E("no memory to create mutex!");
        return RT_NULL;
    }

    kvdb_t kvdb = rt_calloc(1, sizeof(struct kvdb));
    if (kvdb == RT_NULL) {
        LOG_E("no memory to create kvdb!");
        rt_free(mutex);
        return RT_NULL;
    }

    fdb_err_t err = fdb_kvdb_init(&kvdb->db, part, part, RT_NULL, RT_NULL);
    if (err != FDB_NO_ERR) {
        LOG_E("KVDB '%s' not found. Probe failed!", part);
        rt_free(mutex);
        rt_free(kvdb);
        return RT_NULL;
    }

    kvdb->mutex = mutex;
    kvdb->part = part;
    LOG_D("Probed a KVDB | %s | part_name: %s | sec_size: %d | max_size: %d |.", kvdb->db.parent.name, kvdb->db,
          kvdb->db.parent.sec_size, kvdb->db.parent.max_size);
    return kvdb;
}

void kvdb_close(kvdb_t kvdb)
{
    if (kvdb == RT_NULL) {
        LOG_E("invalid kvdb, nullptr!");
        return;
    }

    rt_err_t err = rt_mutex_delete(kvdb->mutex);
    if (err != RT_EOK) {
        LOG_W("delete mutex failed!");
    }

    fdb_err_t db_err = fdb_kvdb_deinit(&kvdb->db);
    if (db_err != FDB_NO_ERR) {
        LOG_E("KVDB '%s' deinit failed!", kvdb->part);
    }

    rt_free(kvdb);
    LOG_D("KVDB '%s' deinit done!", kvdb->part);
}

rt_bool_t kvdb_show(kvdb_t kvdb)
{
    if (kvdb == RT_NULL) {
        LOG_E("invalid kvdb, nullptr!");
        return RT_FALSE;
    }
    rt_mutex_take(kvdb->mutex, RT_WAITING_FOREVER);
    fdb_kv_print(&kvdb->db);
    rt_mutex_release(kvdb->mutex);
    return RT_TRUE;
}

rt_bool_t kvdb_inited(kvdb_t kvdb)
{
    if (kvdb == RT_NULL) {
        LOG_E("invalid kvdb, nullptr!");
        return RT_FALSE;
    }
    return kvdb->db.parent.init_ok;
}

rt_bool_t kvdb_get(kvdb_t kvdb, const char* key, uint8_t* value, size_t* value_len)
{
    if (kvdb == RT_NULL || key == RT_NULL || value == RT_NULL || value_len == RT_NULL) {
        LOG_E("%s: invalid params!", __func__);
        return RT_FALSE;
    }

    struct fdb_blob blob = {0};
    rt_mutex_take(kvdb->mutex, RT_WAITING_FOREVER);
    *value_len = fdb_kv_get_blob(&kvdb->db, key, fdb_blob_make(&blob, value, *value_len));
    rt_mutex_release(kvdb->mutex);
    return *value_len > 0;
}

rt_bool_t kvdb_set(kvdb_t kvdb, const char* key, const uint8_t* value, size_t value_len)
{
    if (kvdb == RT_NULL || key == RT_NULL || value == RT_NULL || value_len == 0) {
        LOG_E("%s: invalid params!", __func__);
        return RT_FALSE;
    }

    struct fdb_blob blob = {0};
    rt_mutex_take(kvdb->mutex, RT_WAITING_FOREVER);
    fdb_err_t err = fdb_kv_set_blob(&kvdb->db, key, fdb_blob_make(&blob, value, value_len));
    rt_mutex_release(kvdb->mutex);
    return err == FDB_NO_ERR;
    ;
}

rt_bool_t kvdb_del(kvdb_t kvdb, const char* key)
{
    if (kvdb == RT_NULL) {
        LOG_E("invalid kvdb, nullptr!");
        return RT_FALSE;
    }
    rt_mutex_take(kvdb->mutex, RT_WAITING_FOREVER);
    fdb_err_t err = fdb_kv_del(&kvdb->db, key);
    rt_mutex_release(kvdb->mutex);
    return err == FDB_NO_ERR;
}
